#include "stdafx.h"

#include "MxUtils\MxError1.h"
#include "..\..\PublicInterfaces\PluginICPopenCV\PluginICPopenCVErrorCodes.h"
#include "PluginICPopenCV.h"

#include <opencv2\core\core.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include <opencv2\imgproc\imgproc_c.h>
#include <opencv2\highgui\highgui.hpp>	//needed for imread(), imwrite()

#include "Utils.h"
#include "BilateralFilterImage.h"


BilateralFilterImage::BilateralFilterImage(void):
	_refCnt(0)
{
}


BilateralFilterImage::~BilateralFilterImage(void)
{
}

bool		MXSTDMETHOD BilateralFilterImage::Invoke(IImageComputeFn *fn, bool DebugMode, bool DisplayMsg)
{
	bool rc = false; 

		if ((fn == nullptr) || (fn->IsValid() == false))
		MX_SETERROR( MX11174, MxError::InvalidParams,  MxError::Abort,  MxError::VerboseReport, "fn is nullptr, or invalid");
	else
	{
		if (   (fn->IsExistParam("StopProc", IImageComputeFnDef::ParamType::Bool, IImageComputeFnDef::Direction::IO) == false)
			|| (fn->IsExistParam("RootFolder", IImageComputeFnDef::ParamType::String, IImageComputeFnDef::Direction::Input) == false)
			|| (fn->IsExistParam("IJC", IImageComputeFnDef::ParamType::String, IImageComputeFnDef::Direction::Input) == false)
			|| (fn->IsExistParam("IJF", IImageComputeFnDef::ParamType::String, IImageComputeFnDef::Direction::Input) == false)
			|| (fn->IsExistParam("ImageRef", IImageComputeFnDef::ParamType::String, IImageComputeFnDef::Direction::IO) == false)
			|| (fn->IsExistParam("Diameter", IImageComputeFnDef::ParamType::Integer, IImageComputeFnDef::Direction::Input) == false)
			|| (fn->IsExistParam("SigmaColor", IImageComputeFnDef::ParamType::Double, IImageComputeFnDef::Direction::Input) == false)
			|| (fn->IsExistParam("SigmaSpace", IImageComputeFnDef::ParamType::Double, IImageComputeFnDef::Direction::Input) == false))
			MX_SETERROR( MX11175, MxError::BadUserInput,  MxError::Abort,  MxError::VerboseReport, "IJCFolder, ImageFolder, ImageRef, Diameter, SigmaColor, SigmaSpace are not supported by this fn");
		else
		{
			if (fn->GetParamBool("StopProc") == true)
			{
				rc = true;
			}
			else
			{
				std::string imageRefDst("");
				std::string imageRef(fn->GetParamStr("ImageRef"));
				std::string pathfilenameSrcImage("");
				std::string pathfilenameDstImage("");
				std::string pathfilenameDebugImage("");

				if (PluginOpenCV::Utils::GetImagePathFilenames(fn, fn->GetParamStr("RootFolder"), fn->GetParamStr("IJC"), fn->GetParamStr("IJF"), imageRef.c_str(),
					fn->GetFileType(), fn->GetFileType(), //if function changes the filetype (.bmp to .jpg) then add to function params the std IO variable ImageProcFilev1::VariableFileTypeName and set it to new filetype before returning - see Job::Run()
					&imageRefDst, &pathfilenameSrcImage, &pathfilenameDstImage, &pathfilenameDebugImage) == false)
					MX_SETERROR(MX11194, MxError::CodeDefect, MxError::Abort, MxError::VerboseReport, "GetImagePathFilenames failed for step=%d", fn->GetSeqNo());
				else
				{
					if (BilateralFilter(pathfilenameSrcImage.c_str(), pathfilenameDstImage.c_str(), fn->GetParamInt("Diameter"), fn->GetParamDouble("SigmaColor"), fn->GetParamDouble("SigmaSpace")) == true)
					{
						if (fn->SetParamStr("ImageRef", imageRefDst.c_str()) == false)
							MX_SETERROR(MX11240, MxError::CodeDefect, MxError::Abort, MxError::QuietReport, "SetParamStr(ImageRef, %s) failed for image %s", imageRefDst.c_str(), imageRef.c_str());
						else
						{
							rc = true;
						}
					}
				}
			}
		}
	}
	return rc;
}

bool		MXSTDMETHOD BilateralFilterImage::BilateralFilter(const char *srcImagePathFilename, const char *destImagePathFilename, int diameter, double sigmaColor, double sigmaSpace)
{
	bool rc = false;

	if ((srcImagePathFilename == nullptr) || (destImagePathFilename == nullptr) )
		MX_SETERROR( MX11176, MxError::InvalidParams,  MxError::Abort,  MxError::VerboseReport, "one or more params is invalid");
	else
	{
		try
		{
			cv::Mat src = cv::imread(srcImagePathFilename, CV_LOAD_IMAGE_ANYDEPTH);
			if (src.data == nullptr)
				MX_SETERROR(MX11177, MxError::BadUserInput,  MxError::Abort,  MxError::VerboseReport, "unable to open source image=%s", srcImagePathFilename);
			else
			{	
				cv::Mat dst = cv::Mat::zeros( src.size(), src.type() );

				cv::bilateralFilter(src, dst, diameter, sigmaColor, sigmaSpace);

				if (cv::imwrite(destImagePathFilename, dst) == false)
					MX_SETERROR(MX11178, MxError::BadUserInput,  MxError::Abort,  MxError::VerboseReport, "unable to write dest image=%s", destImagePathFilename);
				else
				{
					rc = true;
				}
			}
		}
		catch(std::exception& e)
		{
			std::string result("[exception msg not found]");
			MX_SETERROR( MX11189, MxError::CodeDefect,  MxError::Abort,  MxError::QuietReport, "threw exception %s for source image=%s", PluginICPopenCV::GetOpenCVExceptionMsg(e, &result), srcImagePathFilename);
		}
	}
	return rc;
}

long		MXSTDMETHOD BilateralFilterImage::DestroyPtr(void)
{
	long cnt = InterlockedDecrement(&_refCnt);
	if ( cnt == 0 )
		delete this;
	return cnt;
}

long		MXSTDMETHOD BilateralFilterImage::DuplicatePtr(void)
{
	return InterlockedIncrement(&_refCnt);
}

void *		MXSTDMETHOD BilateralFilterImage::Dynamic_cast(const GUID IId)
{
	void *rc = nullptr;

	if ( MxGUID::IsEqual(IId, IMxPluginBaseIID::Guid()))
		rc = static_cast<IMxPluginBase *>(this);
	else
		rc = nullptr;

	std::string tmp;
	if (rc == nullptr)
		MX_SETERROR(MX11179, MxError::Install, MxError::Abort, MxError::QuietReport, "Dynamic_cast does not support IID=%s", MxGUID::ConvertToString(IId, &tmp));
	else
		((IMxPluginBase *)rc)->DuplicatePtr();

	return rc;
}
